﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using VkClientIM.Windows;
using Vkontakte.Api;
using Vkontakte.Api.Database;
using Vkontakte.Api.Operations;

namespace VkClientIM.Logic
{
	public class ApiLogic
	{
		private Profile _myProfile;
		private ApiClient _apiClient;
		private ContactList _contactList;
		private LongPollServerClient _lpsClient=new LongPollServerClient();
		private int _activityUpdateFlag = 0;
		private IPlacesCache _placesCache;
		private Dictionary<long,Conversation> _conversations=new Dictionary<long, Conversation>();
		private IConversationWindow _conversationWindow;
		public ApiLogic(ApiClient client)
		{
			_apiClient = client;
			_myProfile = new Profile( client.MyID );
			_contactList = new ContactList();
			_contactList.NeedProfileUpdate += ContactListNeedProfileUpdate;
			_lpsClient.Failed += LongPollServerConnect;
			_lpsClient.NewMessage += LpsClientNewMessage;
			_lpsClient.UserOnline += LpsClientUserOnline;
			_lpsClient.UserOffline += LpsClientUserOffline;
			 
			_myProfile.PropertyChanged += MyProfilePropertyChanged;
		}

		void ContactListNeedProfileUpdate(long obj)
		{
			ProfilesGet getProfiles = new ProfilesGet();
			getProfiles.Uids.Add(obj);

			getProfiles.Completed += delegate { OnContactUpdate(getProfiles); };
			getProfiles.PersonProperties = PersonProperties.ForIM;
			_apiClient.ExecuteQuerry(getProfiles);
		}


		public void Start()
		{
			if (!_placesCache.IsCountriesInited)
			{
				GetCountries();
			}
			GetMyProfile();
			GetMyStatus();
			GetFriendsLists();
			GetMyFriends();
			LongPollServerConnect();
		}

		public void AttachPlacesCache(IPlacesCache cache)
		{
			_placesCache = cache;
		}

		void LpsClientUserOffline(long user)
		{
			Profile p = _contactList.GetByUserID(user);
			lock (p)
			{
				p.Online = 0;
			}
		}

		void LpsClientUserOnline(long user)
		{
			Profile p= _contactList.GetByUserID( user );
			lock ( p )
			{
				p.Online = 1;
			}
		}

		void LpsClientNewMessage(long messageID, LongPollMessageFlags messageFlags, long userID, long timestamp, string title, string body,string media)
		{
			Message msg = new Message(messageID);
				msg.MessageBody = body;
				msg.MessageTitle = title;
				msg.User = _contactList.GetByUserID(userID, true);
				msg.Out = (messageFlags & LongPollMessageFlags.Outbox) == LongPollMessageFlags.Outbox;
				msg.UnixTime = timestamp;
				if (media != null)
				{

				}
			Profile p = _contactList.GetByUserID(userID, true);
			BeginConversation(p);
			_conversations[userID].AddMessage(msg);
			
		}


		public void BeginConversation(Profile profile)
		{
			if (!_conversations.ContainsKey(profile.UserID))
			{
				if (!_conversations.ContainsKey(profile.UserID))
				{
					Conversation conversation = new Conversation(_myProfile, profile);
					_conversations.Add(profile.UserID, conversation);
				}
			}
			EnshureConversationWindowOpened(_conversations[profile.UserID]);
		}

		internal void EnshureConversationWindowOpened(Conversation c)
		{
			if (_conversationWindow == null)
			{
				ConversationWindow conversationWindow = new ConversationWindow();
				_conversationWindow = conversationWindow;
			}
			if (!_conversationWindow.IsConversationOpened(c))
			{
				_conversationWindow.LoadConversation(c);
			}
			_conversationWindow.Show();
		}

		private void GetCountries()
		{
			PlacesGetCountries q=new PlacesGetCountries();
			q.NeedFull = true;
			q.Completed += delegate
				{
					Country[] countries = q.GetResult();
					for (int i=0;i<countries.Length;i++)
					{
						_placesCache.SaveCountryName(countries[ i ].CountryID,countries[ i ].Title);
					}
				};
			_apiClient.ExecuteQuerry( q );
		}

		private void GetMyProfile()
		{
			ProfilesGet qMy = new ProfilesGet();
			qMy.Uids.Add(_apiClient.MyID);
			qMy.PersonProperties =
				PersonProperties.FirstName |
				PersonProperties.LastName |
				PersonProperties.NickName |
				PersonProperties.Domain |
				PersonProperties.PhotoRec;
			qMy.Completed += delegate
			{
				lock (_myProfile)
				{
					Person[] ret = qMy.GetResult();
					if (ret == null)
					{
						_apiClient.ExecuteQuerry(qMy);
					}
					else
					{
						if (ret.Length != 0)
						{
							Person i = ret[0];
							if (i != null)
							{
								_myProfile.FirstName = i.FirstName;
								_myProfile.LastName = i.LastName;
								_myProfile.NickName = i.NickName;
								_myProfile.Domain = i.Domain + "@vk.com";

								ImageDownloader.DownloadImage(i.PhotoRec,
															   new Action<bool, byte[]>(
																delegate(bool success,
																		  byte[] photo)
																{
																	if (success)
																	{
																		lock (_myProfile)
																		{
																			_myProfile.Photo = photo;
																		}
																	}

																}));

							}

						}
					}
				}
				
			};
			_apiClient.ExecuteQuerry(qMy);
		}

		private void GetMyStatus()
		{
			ActivityGet qMyStatus = new Vkontakte.Api.Operations.ActivityGet();
			qMyStatus.UserID = _apiClient.MyID;
			qMyStatus.Completed += delegate
				{
					lock ( _myProfile )
					{
						ActivityResponce a = qMyStatus.Activity;
						_activityUpdateFlag = 1;

						if ( ( a != null ) && ( a.Activity != null ) )
						{
							_myProfile.Activity = a.Activity;
						}

						_activityUpdateFlag = 0;
					}
				};
			_apiClient.ExecuteQuerry( qMyStatus );
		}

		private void GetFriendsLists()
		{
			FriendsGetLists q=new FriendsGetLists();
			q.Completed += delegate
				{
					var lists= q.GetResult();
					_contactList.LoadGroups( lists );
				};
			_apiClient.ExecuteQuerry(q);
		}

		private void GetMyFriends()
		{
			FriendsGet friendsGet=new FriendsGet();
			friendsGet.PersonProperties = PersonProperties.ForIM;
			friendsGet.Completed += delegate
				{
					#region старый код
					//long[] friendIds= friendsGet.GetShortAnswer();
					//for (int i=0;i<friendIds.Length;i++)
					//{
					//	Profile add = new Profile( friendIds[ i ] );
					//	_contactList.AddProfile( add );
					//}

					// Делим на группы по 50 штук и подгружаем
					//bool flag = true;
					//int pointer = 0;
					//do
					//{
						
					//    ProfilesGet getProfiles = new ProfilesGet();
					//    for ( int i = 0; ( i < 50 ) & ( flag = ( pointer < friendIds.Length ) ); i++,pointer++ )
					//    {
					//        getProfiles.Uids.Add( friendIds[ pointer ] );
					//    }
					//    getProfiles.Completed += delegate { OnContactUpdate( getProfiles ); };
					//    getProfiles.PersonProperties = PersonProperties.ForIM;
					//    _apiClient.ExecuteQuerry( getProfiles );
					//}
					//while ( flag );
					#endregion

					var persons= friendsGet.GetLongAnswer();
					if (persons==null)
					{
						_apiClient.ExecuteHighPriorityQuerry(friendsGet);
						return;
					}
					for (int i=0;i<persons.Length;i++)
					{
						Profile p = new Profile(persons[i].UserID);
						UpdateProfile(p, persons[i]);
						_contactList.AddProfile(p);
					}
				};
			_apiClient.ExecuteQuerry( friendsGet );
		}

		private void LongPollServerConnect()
		{
			MessagesGetLongPollServer q=new MessagesGetLongPollServer();
			q.Completed += delegate
			   {
			        var result = q.GetResult();
					if (result!=null)
					{
						_lpsClient.Start(result);
					}
					else
					{
						_apiClient.ExecuteQuerry(q);
					}

				};
			_apiClient.ExecuteQuerry( q );
		}

		private void OnFriensUpdate(FriendsGet action)
		{
			Person[] persons = action.GetLongAnswer();
			if (persons==null)
			{
				_apiClient.ExecuteQuerry(action);
				return;
			}
			for (int i = 0; i < persons.Length; i++)
			{
				try
				{
					Profile p = _contactList.GetByUserID(persons[i].UserID);
					UpdateProfile(p, persons[i]);
				}
				catch (Exception)
				{
				}

			}
		}

		private void OnContactUpdate(ProfilesGet action)
		{
			Person[] persons= action.GetResult();
			if (persons==null)
			{
				// Такое бывает
				_apiClient.ExecuteQuerry( action );
				return;
			}
			for (int i = 0; i < persons.Length; i++)
			{
				try
				{
					Profile p = _contactList.GetByUserID(persons[i].UserID);
					UpdateProfile(p, persons[i]);
				}
				catch ( Exception )
				{
				}
				
			}
		}

		private void UpdateProfile(Profile profile,Person person)
		{
			if (profile != null)
			{
				lock (profile)
				{
					profile.FirstName = person.FirstName;
					profile.LastName = person.LastName;
					profile.NickName = person.NickName;
					if (person.Domain != null)
					{
						profile.Domain = person.Domain + "@vk.com";
					}
					profile.Online = person.Online;
					profile.PhotoRec = person.PhotoRec;
					ProfileLoadImage(profile, person.PhotoRec);
					UpdateProfileActivity(profile);
				}
			}
		}

		private void UpdateProfileActivity(Profile p)
		{
			ActivityGet qStatus = new Vkontakte.Api.Operations.ActivityGet();
			qStatus.UserID = p.UserID;
			qStatus.Completed += delegate
			{
				lock (p)
				{
					ActivityResponce a = qStatus.Activity;
					if (a != null)
					{
						p.Activity = a.Activity ;
					}
				}
			};
			_apiClient.ExecuteQuerry(qStatus);
		}

		private static void ProfileLoadImage(Profile p, string url)
		{
			ImageDownloader.DownloadImage( url,
			                               new Action<bool, byte[]>(
			                               	delegate( bool success,
			                               	          byte[] photo )
			                               		{
			                               			if ( success )
			                               			{
			                               				lock ( p )
			                               				{
			                               					p.Photo = photo;
			                               				}
			                               			}

			                               		} ) );

		}

		void MyProfilePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			switch ( e.PropertyName )
			{
				case "Activity":
					if (_activityUpdateFlag==0)
					{
						ActivitySet q=new ActivitySet();
						q.Text = _myProfile.Activity;
						_apiClient.ExecuteQuerry( q );
					}
					break;
			}
		}

		private void WorkerThread()
		{
			

		}

		#region Свойства
		public Profile MyProfile
		{
			get { return _myProfile; }
		}

		public ContactList ContactList
		{
			get { return _contactList; }
		}
		#endregion

		#region Функции
		public void Close()
		{
			_apiClient.Dispose();
			_apiClient = null;
		}

		public string GetCountry(int countryID)
		{
			return _placesCache.GetCountryName(countryID);
		}
		#endregion

	}
}
